//***************************************************************************
//   Copyright(c)2022, Xidian University D405.
//   All rights reserved
//
//   IP Name         :   Null
//   File name       :   np_dma_control.v
//   Module name     :   np_dma_control
//   Author          :   Wang Zekun
//   Date            :   2022/06/13
//   Version         :   v1.6 
//   Verison History :   v0.1/v0.2/v1.0/v1.1/v1.2/v1.3/v1.4/1.5/v1.6
//   Edited by       :   Wang Zekun
//   Modification history : v0.1 Initial revision
//                          v0.2 add sequence to solve ar/aw used simultaneously
//                          v1.0 modified based on v0.2,v1.0 is pipeline structure
//                          v1.1 new structure and change module name as np_dma_control
//                               unite rx and tx signals name,add tx module
//                          v1.2 unite address width to parameter and modify tx/rx process flag
//                               desc address 40bit,data address 40bit
//                          v1.3 lock desc address and number at process and 
//                               redefine stop_cnt flag and 
//                               desc_cnt module
//                          v1.4 use timeout_valid_i & _r to write back rdesc and subsent rx process
//                          v1.4.1 update parameter DESC_NUM to 14
//                          v1.5 details in np_dma_decode.v v2.91
//                          v1.6 desc_num could be changed at transmitting.
// ----------------------------------------------------------------------------
// Version 1.6      Date(2022/06/13)
// Abstract : Hardforward DMA unit machine
//-----------------------------------------------------------------------------
// Programmer's model
//                    Null
//-----------------------------------------------------------------------------
//interface list :
//                single pulse Control
module np_dma_control #(
  parameter       AXI_ADDR_WIDTH    = 32,
  parameter       AXI_LIB_WIDTH     = 11,
  parameter       DESC_NUM          = 14    //16384
  )
  (
  input  wire                           m_axi_aclk_i,
  input  wire                           m_axi_aresetn_i,

  input  wire                           rx_port_sel_i,
  output wire                           tx_port_sel_o,
  // from dma decode
    // rx control
  input  wire                           rx_start_i,
  input  wire [AXI_ADDR_WIDTH-1 : 0]    rx_desc_address_i,
    // tx control
  input  wire                           tx_start_i,
  input  wire [AXI_ADDR_WIDTH-1 : 0]    tx_desc_address_i,

  input  wire [127 : 0]                 rx_desc_read_i,
  input  wire                           rx_desc_fifo_rd_empty_i,
  output wire                           rx_desc_fifo_rd_en_o,

  output wire                           rx_desc_fifo_wr_en_o,
  output wire [127 : 0]                 rx_desc_wrback_o,
  input  wire                           rx_desc_fifo_wr_full_i,

  input  wire [127 : 0]                 tx_desc_read_i,
  input  wire                           tx_desc_fifo_rd_empty_i,
  output wire                           tx_desc_fifo_rd_en_o,

  output wire                           tx_desc_fifo_wr_en_o,
  output wire [127 : 0]                 tx_desc_wrback_o,
  input  wire                           tx_desc_fifo_wr_full_i,

  output wire                           rxfifo_length_rd_en_o,
  input  wire [AXI_LIB_WIDTH-1 : 0]     rxfifo_length_dout_i,
  input  wire                           rxfifo_empty_i,

  output wire                           txfifo_length_wr_en_o,
  output wire [AXI_LIB_WIDTH-1 : 0]     txfifo_length_dout_o,
  input  wire                           txfifo_full_i,

  output wire [AXI_ADDR_WIDTH-1 : 0]    axi_aw_addr_o,
  output wire [AXI_LIB_WIDTH-1 : 0]     axi_w_bytes_o,
  output wire                           axi_aw_start_o,
  output wire                           axi_write_desc_type_o,
  output wire                           axi_write_desc_start_o,
  input  wire                           write_desc_ready_i,
  input  wire                           write_data_ready_i,

  output wire [AXI_ADDR_WIDTH-1 : 0]    axi_ar_addr_o,
  output wire [AXI_LIB_WIDTH-1 : 0]     axi_r_bytes_o,
  output wire                           axi_ar_start_o,
  output wire                           axi_read_desc_type_o,
  output wire                           axi_read_desc_start_o,
  input  wire                           read_ready_i,  //axi_to_machine_read_ready_i

  input  wire                           rxfifo_timeout_valid_i,

  input  wire                           write_almost_done_i,
  input  wire                           write_already_done_i,
  input  wire                           read_almost_done_i,
  input  wire                           read_already_done_i,
  input  wire                           read_desc_done_i,
  input  wire                           write_desc_done_i,
  
  //input  wire                           axi_stream_data_done_i,
  output wire [2:0]                     rx_process_flag_o,
  output wire [2:0]                     tx_process_flag_o,
  // interrupt clear
  input  wire                           clr_rx_complete_i,
  input  wire                           clr_tx_complete_i,

  output wire                           rx_ioc_int_o,
  output wire                           tx_ioc_int_o,

  output wire                           rx_complete_int_o,
  output wire                           tx_complete_int_o,

  output wire [AXI_ADDR_WIDTH-1 : 0]    rdesc_addr_current_o,
  output wire [AXI_ADDR_WIDTH-1 : 0]    tdesc_addr_current_o,
  
  input  wire                           rx_tail_halted_i,
  input  wire                           tx_tail_halted_i,

  // new input at v1.1
  input  wire [31:0]                    rx_desc_num_i,
  input  wire [31:0]                    tx_desc_num_i

);

  wire                          rxfifo_write_mem_start;
  wire                          txfifo_read_mem_start;

  reg                           rx_desc_fifo_rd_en_ff1;
  reg                           rx_desc_fifo_rd_en_ff2;
  wire                          rx_desc_fifo_rd_valid;

  reg                           rxfifo_length_rd_en_ff1;
  reg                           rxfifo_length_rd_en_ff2;
  wire                          rxfifo_length_rd_valid;

  reg                           tx_desc_fifo_rd_en_ff1;
  reg                           tx_desc_fifo_rd_en_ff2;
  wire                          tdesc_fifo_rd_valid;

  wire                          rx_desc_parse_valid;
  reg                           rx_parse_over_r;
  wire [AXI_ADDR_WIDTH-1 : 0]   rx_packet_address;
  wire [AXI_LIB_WIDTH-1 : 0]    rx_patcket_length;

  wire                          tx_desc_parse_valid;
  reg                           tx_parse_over_r;
  wire [AXI_ADDR_WIDTH-1 : 0]   tx_packet_address;
  wire [AXI_LIB_WIDTH-1 : 0]    tx_patcket_length;

  reg  [AXI_ADDR_WIDTH-1 : 0]   rdesc_address;//rx_desc_fifo_wr_en_o       --0
  reg  [AXI_ADDR_WIDTH-1 : 0]   tdesc_address;//tx_desc_fifo_wr_en_o       --1

  reg  [AXI_ADDR_WIDTH-1 : 0]   wdata_address;//rx_desc_parse_valid        --2
  wire [AXI_ADDR_WIDTH-1 : 0]   rdata_address;//tx_desc_parse_valid        --2

  wire [AXI_ADDR_WIDTH-1 : 0]   rdesc_address_ar;
  wire [AXI_ADDR_WIDTH-1 : 0]   rdesc_address_aw;
  wire [AXI_LIB_WIDTH-1 : 0]    rdesc_bytes_ar;
  wire [AXI_LIB_WIDTH-1 : 0]    rdesc_bytes_aw;

  wire [AXI_ADDR_WIDTH-1 : 0]   tdesc_address_ar;
  wire [AXI_ADDR_WIDTH-1 : 0]   tdesc_address_aw;
  wire [AXI_LIB_WIDTH-1 : 0]    tdesc_bytes_ar;
  wire [AXI_LIB_WIDTH-1 : 0]    tdesc_bytes_aw;

  wire                          rdesc_32integer_alu;
  wire                          tdesc_32integer_alu;

  reg  [AXI_ADDR_WIDTH-1 : 0]   aw_addr;
  reg  [AXI_LIB_WIDTH-1 : 0]    aw_bytes;
  reg  [2 : 0]                  aw_drawer;
  reg  [2 : 0]                  aw_drawer_clr;
  reg                           aw_rdesc_en;
  reg                           aw_tdesc_en;
  wire                          aw_en;

  reg [AXI_ADDR_WIDTH-1 : 0]    ar_addr;
  reg [AXI_LIB_WIDTH-1 : 0]     ar_bytes;
  reg [2:0]                     ar_drawer;
  reg [2:0]                     ar_drawer_clr;
  reg                           ar_rdesc_en;
  reg                           ar_tdesc_en;
  wire                          ar_en;

  wire [DESC_NUM - 1 : 0]       rx_desc_num_cnt;
  wire [DESC_NUM - 1 : 0]       tx_desc_num_cnt;
  reg  [DESC_NUM - 1 : 0]       rx_desc_num;
  reg  [DESC_NUM - 1 : 0]       tx_desc_num;

  wire                          rx_desc_stop;
  wire                          tx_desc_stop;

  reg  [2 : 0]                  rx_process_flag;
  reg  [2 : 0]                  tx_process_flag;

  reg                           rx_stop_level_r;
  reg                           tx_stop_level_r;

  reg                           rxfifo_timeout_valid_r;
  // interrupt
  wire                          rx_desc_ioc;
  reg                           rx_desc_ioc_r;
  wire                          tx_desc_ioc;
  reg                           tx_desc_ioc_r;

  assign  rxfifo_write_mem_start = rx_start_i;
  assign  txfifo_read_mem_start  = tx_start_i;

  assign  rx_complete_int_o = rx_desc_stop;
  assign  tx_complete_int_o = tx_desc_stop;

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rxfifo_timeout_valid_r <= 1'b0;
    end
    else begin
      rxfifo_timeout_valid_r <= rxfifo_timeout_valid_i;
    end
  end

  // rx tx process state
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rx_process_flag <= 3'b000;
    end
    else if (rxfifo_write_mem_start) begin
      rx_process_flag <= 3'b001;  // read rdesc state
    end
    else if (rx_process_flag[0] & read_desc_done_i) begin
      rx_process_flag <= 3'b010;  // write data state
    end
    else if (rx_process_flag[1] & (rx_desc_stop | rxfifo_timeout_valid_i)) begin
      rx_process_flag <= 3'b100;  // write rdesc state
    end
    else if (rx_process_flag[2] & write_desc_done_i) begin
      rx_process_flag <= 3'b000;
    end
  end
  assign rx_process_flag_o = rx_process_flag;

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tx_process_flag <= 3'b000;
    end
    else if (txfifo_read_mem_start) begin
      tx_process_flag <= 3'b001;  // read tdesc state
    end
    else if (~rx_process_flag[0] & tx_process_flag[0] & read_desc_done_i) begin
      tx_process_flag <= 3'b010;  // read data state
    end
    else if (tx_process_flag[1] & tx_desc_stop) begin
      tx_process_flag <= 3'b100;  // write tdesc state
    end
    else if (~rx_process_flag[2] & tx_process_flag[2] & write_desc_done_i) begin
      tx_process_flag <= 3'b000;
    end
  end
  assign tx_process_flag_o = tx_process_flag;

  /***********************************************************/
  /***********************************************************/
  /***********************************************************/
  //store rdesc address
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rdesc_address  <= {AXI_ADDR_WIDTH{1'b0}};
      //rx_desc_num    <= {DESC_NUM{1'b1}};
    end
    else if(~(|rx_process_flag)) begin
      rdesc_address  <= rx_desc_address_i;
      //rx_desc_num    <= rx_desc_num_i[DESC_NUM-1:0];
    end
    else begin
      rdesc_address  <= rdesc_address;
      //rx_desc_num    <= rx_desc_num  ;
    end
  end

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rx_desc_num    <= {DESC_NUM{1'b1}};
    end
    else begin
      rx_desc_num    <= rx_desc_num_i[DESC_NUM-1:0];
    end
  end
  
  //assign rdesc_address = rx_desc_address_i;
  //assign rdesc_bytes = {rx_desc_num_i[AXI_LIB_WIDTH-5:0],4'b0000};

  //store rx_pkt address
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      wdata_address  <= {AXI_ADDR_WIDTH{1'b0}};
    end
    else if(rx_desc_parse_valid) begin
      wdata_address  <= rx_packet_address;
    end
    else begin
      wdata_address  <= wdata_address;
    end
  end

  //store tdesc address
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tdesc_address  <= {AXI_ADDR_WIDTH{1'b0}};
      //tx_desc_num    <= {DESC_NUM{1'b1}};
    end
    else if(~(|tx_process_flag)) begin
      tdesc_address  <= tx_desc_address_i;
      //tx_desc_num    <= tx_desc_num_i[DESC_NUM-1:0];
    end
    else begin
      tdesc_address  <= tdesc_address;
      //tx_desc_num    <= tx_desc_num  ;
    end
  end

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tx_desc_num    <= {DESC_NUM{1'b1}};
    end
    else begin
      tx_desc_num    <= tx_desc_num_i[DESC_NUM-1:0];
    end
  end
  
  assign rdata_address = tx_packet_address;

  np_dma_desc_cnt #(
    .AXI_LIB_WIDTH   (AXI_LIB_WIDTH),
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .DESC_NUM        (DESC_NUM)
   )u_np_dma_rdesc_cnt(
    .clk_i             (m_axi_aclk_i),
    .resetn_i          (m_axi_aresetn_i),
    .load_en_i         (rxfifo_write_mem_start),
    .load_desc_num_i   (rx_desc_num),
    .base_address_i    (rdesc_address),
    .desc_cnt_en_i     (rx_desc_fifo_wr_en_o),//(rx_desc_parse_valid),//
    .clr_en_i          (rx_stop_level_r),
    .rxfifo_timeout_valid_i (rxfifo_timeout_valid_i | rxfifo_timeout_valid_r),
    .channel_ready_i   (write_desc_ready_i),

    .cnt_stop_o                 (rx_desc_stop),
    .cnt_data_o                 (rx_desc_num_cnt),
    .desc_bytes_ar_o            (rdesc_bytes_ar),
    .desc_bytes_aw_o            (rdesc_bytes_aw),
    .cntr_32_integer_pulse_o    (rdesc_32integer_alu),
    .desc_addr_ar_o             (rdesc_address_ar),
    .desc_addr_aw_o             (rdesc_address_aw),
    .desc_addr_current_o        (rdesc_addr_current_o)
  );

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rx_stop_level_r <= 1'b0;
    end
    else if ((rx_desc_stop | rxfifo_timeout_valid_i) & (|rx_process_flag)) begin
      rx_stop_level_r <= 1'b1;
    end
    else if (write_already_done_i | write_desc_done_i) begin
      rx_stop_level_r <= 1'b0;
    end
    else begin
      rx_stop_level_r <= rx_stop_level_r;
    end
  end

  np_dma_desc_cnt #(
    .AXI_LIB_WIDTH   (AXI_LIB_WIDTH),
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .DESC_NUM        (DESC_NUM)
   )u_np_dma_tdesc_cnt(
    .clk_i             (m_axi_aclk_i),
    .resetn_i          (m_axi_aresetn_i),
    .load_en_i         (txfifo_read_mem_start),
    .load_desc_num_i   (tx_desc_num),
    .base_address_i    (tdesc_address),
    .desc_cnt_en_i     (tx_desc_fifo_wr_en_o),//(tx_desc_parse_valid),//
    .clr_en_i          (tx_stop_level_r),
    .rxfifo_timeout_valid_i (1'b0),
    .channel_ready_i   (write_desc_ready_i),

    .cnt_stop_o                 (tx_desc_stop),
    .cnt_data_o                 (tx_desc_num_cnt),
    .desc_bytes_ar_o            (tdesc_bytes_ar),
    .desc_bytes_aw_o            (tdesc_bytes_aw),
    .cntr_32_integer_pulse_o    (tdesc_32integer_alu),
    .desc_addr_ar_o             (tdesc_address_ar),
    .desc_addr_aw_o             (tdesc_address_aw),
    .desc_addr_current_o        (tdesc_addr_current_o)
  );
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tx_stop_level_r <= 1'b0;
    end
    else if (tx_desc_stop & (|tx_process_flag)) begin
      tx_stop_level_r <= 1'b1;
    end
    else if (read_already_done_i) begin
      tx_stop_level_r <= 1'b0;
    end
    else begin
      tx_stop_level_r <= tx_stop_level_r;
    end
  end

  /***********************************************************/
  /***********************************************************/
  /***********************************************************/
  // aw process priority : first--->write rdesc
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      aw_drawer[0] <= 1'b0;
    end
    else if (rx_desc_stop | rdesc_32integer_alu | rxfifo_timeout_valid_r) begin
    //else if (rx_stop_level_r & (write_already_done_i)| rdesc_32integer_alu | rxfifo_timeout_valid_r) begin
      aw_drawer[0] <= 1'b1;
    end
    else if (aw_drawer_clr[0]) begin
      aw_drawer[0] <= 1'b0;
    end
    else begin
      aw_drawer[0] <= aw_drawer[0];
    end
  end

  // aw process priority : second--->write tdesc
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      aw_drawer[1] <= 1'b0;
    end
    else if (tx_desc_stop | tdesc_32integer_alu) begin
    //else if (tx_stop_level_r & read_already_done_i | tdesc_32integer_alu) begin
      aw_drawer[1] <= 1'b1;
    end
    else if (aw_drawer_clr[1]) begin
      aw_drawer[1] <= 1'b0;
    end
    else begin
      aw_drawer[1] <= aw_drawer[1];
    end
  end

  // aw process priority : third--->write data
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      aw_drawer[2] <= 1'b0;
    end
    else if (rx_desc_parse_valid) begin
      aw_drawer[2] <= 1'b1;
    end
    else if (aw_drawer_clr[2] | rxfifo_timeout_valid_r) begin
      aw_drawer[2] <= 1'b0;
    end
    else begin
      aw_drawer[2] <= aw_drawer[2];
    end
  end
  
  always @(*) begin
    case (aw_drawer)
      3'b001,3'b011,3'b101,3'b111: begin
        aw_drawer_clr = write_desc_ready_i ? 3'b001 : 3'b000;
        aw_addr       = write_desc_ready_i ? rdesc_address_aw : {AXI_ADDR_WIDTH{1'b0}};
        aw_bytes      = write_desc_ready_i ? rdesc_bytes_aw : {AXI_LIB_WIDTH{1'b0}};
        aw_rdesc_en   = write_desc_ready_i ? 1'b1 : 1'b0;
        aw_tdesc_en   = 1'b0;
        rx_parse_over_r  = 1'b0;
      end
      3'b010,3'b110: begin
        aw_drawer_clr = write_desc_ready_i ? 3'b010 : 3'b000;
        aw_addr       = write_desc_ready_i ? tdesc_address_aw : {AXI_ADDR_WIDTH{1'b0}};
        aw_bytes      = write_desc_ready_i ? tdesc_bytes_aw : {AXI_LIB_WIDTH{1'b0}};
        aw_rdesc_en   = 1'b0;
        aw_tdesc_en   = write_desc_ready_i ? 1'b1 : 1'b0;
        rx_parse_over_r  = 1'b0;
      end
      3'b100: begin
        aw_drawer_clr = write_data_ready_i ? 3'b100 : 3'b000;
        aw_addr       = write_data_ready_i ? wdata_address : {AXI_ADDR_WIDTH{1'b0}};
        aw_bytes      = write_data_ready_i ? rx_patcket_length : {AXI_LIB_WIDTH{1'b0}};
        aw_rdesc_en   = 1'b0;
        aw_tdesc_en   = 1'b0;
        rx_parse_over_r  = write_data_ready_i ? 1'b1 : 1'b0;
      end
      default: begin
        aw_drawer_clr = 3'b000;
        aw_addr       = {AXI_ADDR_WIDTH{1'b0}};
        aw_bytes      = {AXI_LIB_WIDTH{1'b0}};
        aw_rdesc_en   = 1'b0;
        aw_tdesc_en   = 1'b0;
        rx_parse_over_r  = 1'b0;
      end 
    endcase
  end

  assign aw_en = aw_rdesc_en | aw_tdesc_en | rx_parse_over_r;
  
  assign axi_aw_addr_o          = aw_addr; // packet_address / rdesc_address / tdesc_address
  assign axi_w_bytes_o          = aw_bytes; // packet_length / rdesc size /tdesc size
  assign axi_aw_start_o         = aw_en; // packet req / rdesc req / tdesc req
  assign axi_write_desc_start_o = aw_rdesc_en | aw_tdesc_en; // rdesc req / tdesc req
  assign axi_write_desc_type_o  = aw_tdesc_en; //0 -- rdesc,1 -- tdesc
  /*
  assign axi_aw_addr_o          = axi_write_desc_start_o ? rdesc_address : rx_packet_address;// packet_address / rdesc_address / tdesc_address
  assign axi_w_bytes_o          = axi_write_desc_start_o ? rdesc_bytes : rx_patcket_length;// packet_length / rdesc size /tdesc size
  assign axi_aw_start_o         = rx_desc_parse_valid | axi_write_desc_start_o; // packet req / rdesc req / tdesc req
  assign axi_write_desc_start_o = rx_desc_stop & write_already_done_i; // rdesc req / tdesc req
  assign axi_write_desc_type_o  = 1'b0; //0 -- rdesc,1 -- tdesc
  */

  /***********************************************************/
  /***********************************************************/
  /***********************************************************/

  // ar process priority : first--->read rdesc
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      ar_drawer[0] <= 1'b0;
    end
    else if (rxfifo_write_mem_start | (rdesc_32integer_alu & ~rx_desc_stop)) begin  // do not need to save in draw, because of priority
      ar_drawer[0] <= 1'b1;
    end
    else if (ar_drawer_clr[0]) begin
      ar_drawer[0] <= 1'b0;
    end
    else begin
      ar_drawer[0] <= ar_drawer[0];
    end
  end

  // ar process priority : second--->read tdesc
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      ar_drawer[1] <= 1'b0;
    end
    else if (txfifo_read_mem_start | (tdesc_32integer_alu & ~tx_desc_stop)) begin // save signals in draw
      ar_drawer[1] <= 1'b1;
    end
    else if (ar_drawer_clr[1]) begin // take out signals from draw
      ar_drawer[1] <= 1'b0;
    end
    else begin
      ar_drawer[1] <= ar_drawer[1];
    end
  end

  // ar process priority : third--->read data
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      ar_drawer[2] <= 1'b0;
    end
    else if (tx_desc_parse_valid) begin // save signals in draw
      ar_drawer[2] <= 1'b1;
    end
    else if (ar_drawer_clr[2]) begin // take out signals from draw
      ar_drawer[2] <= 1'b0;
    end
    else begin
      ar_drawer[2] <= ar_drawer[2];
    end
  end
  
  always @(*) begin
    case (ar_drawer)
      3'b001,3'b011,3'b101,3'b111: begin
        ar_drawer_clr = ~rx_tail_halted_i & read_ready_i ? 3'b001 : 3'b000;
        ar_addr       = ~rx_tail_halted_i & read_ready_i ? rdesc_address_ar : {AXI_ADDR_WIDTH{1'b0}};
        ar_bytes      = ~rx_tail_halted_i & read_ready_i ? rdesc_bytes_ar : {AXI_LIB_WIDTH{1'b0}};
        ar_rdesc_en   = ~rx_tail_halted_i & read_ready_i ? 1'b1 : 1'b0;
        ar_tdesc_en   = 1'b0;
        tx_parse_over_r  = 1'b0;
      end
      3'b010,3'b110: begin
        ar_drawer_clr = ~tx_tail_halted_i & read_ready_i ? 3'b010 : 3'b000;
        ar_addr       = ~tx_tail_halted_i & read_ready_i ? tdesc_address_ar : {AXI_ADDR_WIDTH{1'b0}};
        ar_bytes      = ~tx_tail_halted_i & read_ready_i ? tdesc_bytes_ar : {AXI_LIB_WIDTH{1'b0}};
        ar_rdesc_en   = 1'b0;
        ar_tdesc_en   = ~tx_tail_halted_i & read_ready_i ? 1'b1 : 1'b0;
        tx_parse_over_r  = 1'b0;
      end
      3'b100: begin
        ar_drawer_clr = read_ready_i ? 3'b100 : 3'b000;
        ar_addr       = read_ready_i ? rdata_address : {AXI_ADDR_WIDTH{1'b0}};
        ar_bytes      = read_ready_i ? tx_patcket_length : {AXI_LIB_WIDTH{1'b0}};
        ar_rdesc_en   = 1'b0;
        ar_tdesc_en   = 1'b0;
        tx_parse_over_r  = read_ready_i ? 1'b1 : 1'b0;
      end
      default: begin
        ar_drawer_clr = 3'b000;
        ar_addr       = {AXI_ADDR_WIDTH{1'b0}};
        ar_bytes      = {AXI_LIB_WIDTH{1'b0}};
        ar_rdesc_en   = 1'b0;
        ar_tdesc_en   = 1'b0;
        tx_parse_over_r  = 1'b0;
      end 
    endcase
  end
  
  assign ar_en = tx_parse_over_r | ar_rdesc_en | ar_tdesc_en;

  assign axi_ar_addr_o          = ar_addr;    // packet address / rdesc address / tdesc address
  assign axi_r_bytes_o          = ar_bytes;   // packet length / rdesc size /tdesc size
  assign axi_ar_start_o         = ar_en;      // packet req / rdesc req / tdesc req
  assign axi_read_desc_start_o  = ar_rdesc_en | ar_tdesc_en; // rdesc req / tdesc req
  assign axi_read_desc_type_o   = ar_tdesc_en; //0 -- rdesc,1 -- tdesc
  
  /*
  assign axi_ar_addr_o          = rxfifo_write_mem_start ? rdesc_address : {AXI_ADDR_WIDTH{1'b0}}; // packet address / rdesc address / tdesc address
  assign axi_r_bytes_o          = rxfifo_write_mem_start ? rdesc_bytes   : {AXI_LIB_WIDTH{1'b0}}; // packet length / rdesc size /tdesc size
  assign axi_ar_start_o         = rxfifo_write_mem_start | txfifo_read_mem_start; // packet req / rdesc req / tdesc req
  assign axi_read_desc_start_o  = rxfifo_write_mem_start | txfifo_read_mem_start; // rdesc req / tdesc req
  assign axi_read_desc_type_o   = 1'b0; //0 -- rdesc,1 -- tdesc
  */

  /***********************************************************/
  /***********************************************************/
  /***********************************************************/
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rx_desc_fifo_rd_en_ff1  <= 1'b0;
      rx_desc_fifo_rd_en_ff2  <= 1'b0;
      rxfifo_length_rd_en_ff1 <= 1'b0;
      rxfifo_length_rd_en_ff2 <= 1'b0;
    end
    else begin
      rx_desc_fifo_rd_en_ff1  <= rx_desc_fifo_rd_en_o;
      rx_desc_fifo_rd_en_ff2  <= rx_desc_fifo_rd_en_ff1;
      rxfifo_length_rd_en_ff1 <= rx_desc_fifo_rd_en_o;
      rxfifo_length_rd_en_ff2 <= rxfifo_length_rd_en_ff1;
      //rx_desc_fifo_rd_valid <= rx_desc_fifo_rd_en_o;
      //rxfifo_length_rd_valid <= rxfifo_length_rd_en_o;
    end
  end

  assign rx_desc_fifo_rd_valid  = rx_desc_fifo_rd_en_ff2;
  assign rxfifo_length_rd_valid = rxfifo_length_rd_en_ff2;
  assign rxfifo_length_rd_en_o  = rx_desc_fifo_rd_en_o;
  //assign rxfifo_length_rd_en_o  = rx_desc_fifo_rd_en_ff1;
  
  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      rx_desc_ioc_r <= 1'b0;
    end
    else if (rx_parse_over_r) begin
      rx_desc_ioc_r <= rx_desc_ioc;
    end
    else begin
      rx_desc_ioc_r <= rx_desc_ioc_r;
    end
  end
  assign rx_ioc_int_o = write_almost_done_i ? rx_desc_ioc_r : 1'b0;

  np_dma_rx_desc #(
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .AXI_LIB_WIDTH   (AXI_LIB_WIDTH)
   ) u_np_dma_rx_desc(
    .clk_i                            (m_axi_aclk_i),
    .resetn_i                         (m_axi_aresetn_i),

    .rx_start_en_i                    (rxfifo_write_mem_start),
    .rx_start_circle_i                (write_almost_done_i | rxfifo_write_mem_start),
    // rx desc
    .rx_descfifo_read_en_o            (rx_desc_fifo_rd_en_o),
    .rx_desc_fifo_rd_empty_i          (rx_desc_fifo_rd_empty_i),
    .rx_desc_read_valid_i             (rx_desc_fifo_rd_valid),
    .rx_desc_i                        (rx_desc_read_i),
    // rx data
    .rx_fifo_empty_i                  (rxfifo_empty_i),
    .rx_patcket_length_valid_i        (rxfifo_length_rd_valid),
    .rx_patcket_length_i              (rxfifo_length_dout_i),
    .rx_port_status_i                 (rx_port_sel_i),

    .rx_desc_constr_valid_o           (rx_desc_fifo_wr_en_o),
    .rx_desc_o                        (rx_desc_wrback_o),

    .rx_desc_parse_valid_o            (rx_desc_parse_valid),
    .rx_packet_address_o              (rx_packet_address),
    .rx_patcket_length_o              (rx_patcket_length),
    .rx_desc_ioc_o                    (rx_desc_ioc),
    .rx_desc_own_o                    ()
  );

  /***********************************************************/
  /***********************************************************/
  /***********************************************************/

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tx_desc_fifo_rd_en_ff1 <= 1'b0;
      tx_desc_fifo_rd_en_ff2 <= 1'b0;
      //tdesc_fifo_rd_valid <= 1'b0;
    end
    else begin
      tx_desc_fifo_rd_en_ff1 <= tx_desc_fifo_rd_en_o;
      tx_desc_fifo_rd_en_ff2 <= tx_desc_fifo_rd_en_ff1;
      //tdesc_fifo_rd_valid <= tx_desc_fifo_rd_en_o;
    end
  end

  assign tdesc_fifo_rd_valid = tx_desc_fifo_rd_en_ff2;

  always @(posedge m_axi_aclk_i or negedge m_axi_aresetn_i) begin
    if(~m_axi_aresetn_i) begin
      tx_desc_ioc_r <= 1'b0;
    end
    else if (tx_parse_over_r) begin
      tx_desc_ioc_r <= tx_desc_ioc;
    end
    else begin
      tx_desc_ioc_r <= tx_desc_ioc_r;
    end
  end
  assign tx_ioc_int_o = read_almost_done_i ? tx_desc_ioc_r : 1'b0;

  np_dma_tx_desc #(
    .AXI_ADDR_WIDTH  (AXI_ADDR_WIDTH),
    .AXI_LIB_WIDTH   (AXI_LIB_WIDTH)
   ) u_np_dma_tx_desc(
    .clk_i                            (m_axi_aclk_i),
    .resetn_i                         (m_axi_aresetn_i),
    
    .read_already_done_i              (read_already_done_i & tx_process_flag[1]),

    .tx_start_en_i                    (txfifo_read_mem_start),
    .tx_start_circle_i                (read_almost_done_i & tx_process_flag[1] | txfifo_read_mem_start),
    // tx desc
    .tx_descfifo_read_en_o            (tx_desc_fifo_rd_en_o),
    .tx_desc_fifo_rd_empty_i          (tx_desc_fifo_rd_empty_i),
    .tx_desc_read_valid_i             (tdesc_fifo_rd_valid),
    .tx_desc_i                        (tx_desc_read_i),
    // tx data
    .tx_fifo_full_i                   (txfifo_full_i),
    .tx_patcket_length_valid_i        (tdesc_fifo_rd_valid),
    //.tx_patcket_length_i              (txfifo_length_dout_i),
    //.tx_port_status_i                 (tx_port_sel_i),

    .tx_desc_constr_valid_o           (tx_desc_fifo_wr_en_o),
    .tx_desc_o                        (tx_desc_wrback_o),

    .tx_desc_parse_valid_o            (tx_desc_parse_valid),
    .tx_packet_address_o              (tx_packet_address),
    .tx_patcket_length_o              (tx_patcket_length),
    .tx_port_status_o                 (tx_port_sel_o),
    .tx_desc_ioc_o                    (tx_desc_ioc),
    .tx_desc_own_o                    ()
  );
  assign txfifo_length_dout_o  = tx_patcket_length;
  assign txfifo_length_wr_en_o = tx_desc_parse_valid;
endmodule